package view;
import model.*;

/**
 * The ConsoleView class provides a simple, text based way
 * to visualise the game of turn based pacman. In it's current
 * implementation, this class does not support accurate display
 * of one sided walls and portals. This class is primarily for
 * early game play testing purposes.
 * 
 * @author Alexander Craig
 */
public class ConsoleView implements GameListener {
	
	/**Message displayed if the level was passed.*/
	private static final String MSG_LEVEL_WON = "Great Success!";
	/**Message displayed if the player lost the game.*/
	private static final String MSG_GAME_OVER = "You're out of lives. GG.";
	/**Message displayed if a life was lost.*/
	private static final String MSG_DEATH = "OMM NOM NOM. You die.";
	
	/** the symbols used to construct the map */
	private static final char GHOST_SYMBOL = 'G';
	private static final char PLAYER_SYMBOL = 'P';
	private static final char DOT = '.';
	private static final char EMPTY_TILE = ' ';
	private static final char HORIZONTAL_WALL = '_';
	private static final char VERTICAL_WALL = '|';
	
	/**
	 * Default Constructor
	 */
	public ConsoleView() {
	}
	
	/**
	 * Constructs the ConsolveView, and starts it listening to
	 * a given GameModel.
	 * @param model	the game model to watch
	 */
	public ConsoleView(GameModel model) {
		model.addGameListener(this);
	}
	/**
	 * Draws a graphical representation of a pacman maze to the
	 * console.
	 * @param maze	the maze to draw
	 */
	public void drawMaze(GameModel model) {
		Maze maze = model.getMaze();
		int x, y;
		
		// Generate a new character array to store the maze view
		int maxX = (maze.getMaxX() * 2) + 1;
		int maxY = (maze.getMaxY() * 2) + 1;
		char mazeView[][] = new char[maxX][maxY];
		
		// Sets the entire character array to spaces
		for (x = 0; x < maxX; x++) {
			for (y = 0; y < maxY; y++) {
				mazeView[x][y] = EMPTY_TILE;
			}
		}
		
		for (Tile t : maze) {
			x = t.getXCoord() * 2 + 1;
			y = t.getYCoord() * 2 + 1;
			
			// Draw the tile itself to the character array
			if (t.hasDot()) {
				mazeView[x][y] = DOT;
			} else {
				mazeView[x][y] = EMPTY_TILE;
			}
			
			if(model.getPlayer().getTile() == t) {
				mazeView[x][y] = PLAYER_SYMBOL;
			}
			
			for(int i = 0; i < model.getNumGhosts(); i++) {
				if (model.getGhost(i).getTile() == t) {
					mazeView[x][y] = GHOST_SYMBOL;
				}
			}
			
			// Draw adjoining walls to the character array
			if (t.getExit(Direction.NORTH) == null) {
				mazeView[x][y-1] = HORIZONTAL_WALL;
				if (mazeView[x+1][y-1] == EMPTY_TILE)
					mazeView[x+1][y-1] = HORIZONTAL_WALL;
				if (mazeView[x-1][y-1] == EMPTY_TILE)
					mazeView[x-1][y-1] = HORIZONTAL_WALL;
			}
			if (t.getExit(Direction.SOUTH) == null) {
				mazeView[x][y+1] = HORIZONTAL_WALL;
				if (mazeView[x+1][y+1] == EMPTY_TILE)
					mazeView[x+1][y+1] = HORIZONTAL_WALL;
				if (mazeView[x-1][y+1] == EMPTY_TILE)
					mazeView[x-1][y+1] = HORIZONTAL_WALL;
			}
			if (t.getExit(Direction.WEST) == null) {
				mazeView[x-1][y] = VERTICAL_WALL;
				mazeView[x-1][y+1] = VERTICAL_WALL;
			}
			if (t.getExit(Direction.EAST) == null) {
				mazeView[x+1][y] = VERTICAL_WALL;
				mazeView[x+1][y+1] = VERTICAL_WALL;
			}
		}
		
		// Draw the character array to the console
		for (y = 0; y < maxY; y++) {
			for (x = 0; x < maxX; x++) {
				System.out.print(mazeView[x][y]);
			}
			System.out.println();
		}

	}
	
	/**
	 * This function will be called whenever the player successfully makes a move.
	 * @param EventObject	stores the source and additional details on the event
	 */
	public void playerMove(GameEvent event)
	{
		for(int i = 0; i < (event.getSource().getMaze().getMaxX() * 2) + 1; i++) {
			System.out.print("_");
		}
		System.out.println();
		System.out.println("Dots: " + event.getSource().getMaze().dotsRemaining() + 
				"       Lives: " + event.getSource().getPlayer().getLives());
		System.out.println("Dots Required to Pass: " + event.getSource().getMaze().getPassDots());
		drawMaze(event.getSource());
	}
	
	/**
	 * This function will be called whenever the player dies.
	 * @param EventObject	stores the source and additional details on the event
	 */
	public void playerDeath(GameEvent event)
	{
		System.out.println();
		System.out.println(MSG_DEATH);
		System.out.println();
	}
	
	/**
	 * This function will be called if the player loses all their lives.
	 * @param EventObject	stores the source and additional details on the event
	 */
	public void gameOver(GameEvent event)
	{
		System.out.println();
		System.out.println(MSG_GAME_OVER);
		System.out.println();
	}
	
	/**
	 * This function will be called when every dot on the grid has been collected.
	 * @param EventObject	stores the source and additional details on the event
	 */
	public void levelComplete(GameEvent event)
	{
		System.out.println();
		System.out.println(MSG_LEVEL_WON);
		System.out.println();
	}

	@Override
	public void newGame(GameEvent event) {
		
	}
	@Override
	public void levelReset(GameEvent event) {
	}

}
